home *** CD-ROM | disk | FTP | other *** search
- /*****************************************************************************/
- /* */
- /* */
- /* ***** ***** */
- /* ***** ***** */
- /* ***** ***** */
- /* ***** ***** */
- /* *************** *************** */
- /* ***************** ***************** */
- /* *************** *************** */
- /* ***** ***** TheNet */
- /* ***** ***** Portable. Compatible. */
- /* ***** ***** Public Domain */
- /* ***** ***** NORD><LINK */
- /* */
- /* This software is public domain ONLY for non commercial use */
- /* */
- /* */
- /*****************************************************************************/
-
- /* Level 3, Routing */
- /* Version 1.01 */
- /* Hans Georg Giese, DF2AU, Hinter dem Berge 5, 3300 Braunschweig */
- /* 14-MAY-88 */
- /* Modified G8KBB April 1991
- * include support for bank switching in TNC2
- * use register keyword for code efficiency
- * use all.h header file
- * make nodes broadcast on ports optional
- * implement modified nodes bcast algo conditionally on MODIFIED
- * implement optional RS232 nodes broadcast interval on MODIFIED
- * include level 3 stats optionally on STATSCMD
- * implement access control functions optionally on ACL definition
- * remove unnecessary '== 1' and similar constructs
- * add integrity checking rather than using isrout()
- * add noslime controls
- * use faster macro for cpy6ch & move4b if feasible
- *
- * September 1993 - released as TheNet X-1J
- */
-
- #include "all.h"
- #include "tntyp.h" /* Definition der Typen */
-
- #ifdef BANKED
- #define EXTERN extern
- #else
- #define EXTERN
- #endif
-
- #include "tnl3v.h" /* Definition der eigenen Variablen */
- #include "tnl3e.h" /* externe Deklarationen */
-
- /*---------------------------------------------------------------------------*/
- /* Strings fuer Level3 */
- char brodes[] = /* Ziel (Rundsprueche) */
- /* ASCII Call */
- /* SSID links geschoben */
- {'N','O','D','E','S',' ','\140'};
- char brodil[] = {'\000'}; /* Digiliste (Rundsprueche) */
- /* Call im Standardformat */
- /* Listenende = 0 */
- #ifndef BANKED
- char nulide[] = /* leerer Ident */
- {' ',' ',' ',' ',' ',' '};
- #else
- extern char nulide[];
- #endif
-
- /*---------------------------------------------------------------------------*/
- VOID l3init() /* Level 3 initialisieren */
- {
- register nbrtyp *nbrpoi; /* Pointer auf Nachbarn */
-
- numdes = 0; /* Ziel Liste ist leer */
- inithd(&l3rxfl); /* Liste empfangene Frames loeschen */
- inithd(&l3txl); /* Liste zu sendende Frames loeschen */
- #ifdef STATSCMD
- l3gwcnt[0] = l3gwcnt[1] = 0; /* clear level 3 stats counters */
- #endif
- if (!iswarm()) /* nur im Kaltstart */
- {
- inithd(&destil); /* Liste Ziele loeschen */
- inithd(&neigbl); /* Liste Nachbarn loeschen */
- maxdes = DEFDES; /* Ziele maximal */
- broint = DEFBRI; /* Rundspruch Intervall */
- obcini = DEFOBC; /* Abwesenheitszaehler */
- obcbro = DEFOBB; /* maximale Abwesenheit fuer Rundspruch */
- worqua = DEFWQU; /* Qualitaet fuer Rundspruch minimal */
- timliv = DEFTLI; /* Paketlebensdauer */
- ch0qua = DEFCH0; /* Kanal 0 Qualitaet */
- ch1qua = DEFCH1; /* Kanal 1 Qualitaet */
- #ifdef MODIFIED
- brochn = DEFBCN; /* channels for node broadcast control */
- br1int = DEFBR1; /* default nodes bcast interval in seconds */
- broalg = DEFALG; /* default algorithm control flags */
- #endif
- }
- else /* Warmstart */
- {
-
- /* integrity checking is done here for all tables. This should be
- * for all linked lists of tables that should be maintained. These
- * are defined according to the options compiled in but include the
- * ACL, netrom neighbour & destination, IP route and ARP tables.
- * Calling integrity with a null parameter instructs it to check
- * that the tables are linked and do not point to rubbish.
- */
- #ifdef INTEGRITY
- integrity( NULL );
- #endif
- for (despoi = (nodtyp *) destil.lnext; /* Zielliste bearbeiten */
- despoi != (nodtyp *) &destil.lnext;
- despoi = (nodtyp *) despoi->nodlnk.lnext)
- {
- #ifdef PK96
- kick_wdog();
- #endif
- if (despoi->nodcal[0] != 0) /* Eintrag belegt? */
- {
- numdes += 1; /* ein Ziel mehr */
- despoi->actrou = 0; /* kein aktiver Weg */
- inithd(&despoi->nodinf); /* keine Info fuer dieses Ziel */
- }
- else /* leerer Eintrag */
- {
- unlink((despoi = (nodtyp *)despoi->nodlnk.lprev)->nodlnk.lnext);
- }
- }
- for (nbrpoi = (nbrtyp *) neigbl.lnext; /* Nachbarn Liste bearbeiten */
- nbrpoi != (nbrtyp *) &neigbl.lnext;
- nbrpoi = (nbrtyp *) nbrpoi->nbrlnk.lnext)
- {
- nbrpoi->nbrl2l = 0; /* Querverweis in L2Link loeschen */
- }
- }
- brotim = broint > 60 ? broint - 60 : 0; /* set node b'cast current timer */
- #ifdef MODIFIED
- br1tim = br1int > 60 ? br1int - 60 : 0; /* set RS232 nodes bcast timer */
- #endif
- }
-
- /*---------------------------------------------------------------------------*/
- VOID l3serv() /* Level 3 Service */
- {
- char orgnod[7]; /* Call des Quellknotens */
- char desnod[7]; /* Call des Zielknotens */
- char beaide[6]; /* Ident des Rundspruch sendenden Knotens */
- char nbrcal[7]; /* Call des Nachbarn */
- char *rxnxt; /* erstes Zeichen im Frame */
- char *nxtsav; /* Zwischenspeicher fuer erstes Zeichen */
- BOOLEAN destin; /* aktuelles Ziel */
- register unsigned cnt; /* Scratch Zaehler */
- register mhtyp *mbhd; /* Kopf des aktuellen Frames */
- unsigned chaqua; /* Qualitaet des aktuellen Kanals */
- unsigned getsav; /* Zwischenspeicher fuer Getcount */
- register unsigned rxgetc; /* Getcount des Frames */
-
- /*=== empfangene Frames verarbeiten ===*/
- while ((mbhd = (mhtyp *) l3rxfl.lnext) != (mhtyp *) &l3rxfl) /* Liste leer?*/
- {
- unlink(mbhd); /* Frame aus Kette loesen */
- if ((mbhd->pid & 0xff) == PID_NETROM) /* PID stimmt? */
- {
- rxnxt = mbhd->nxtchr; /* erstes Zeichen des Frames und */
- rxgetc = mbhd->getcnt; /* Getcount merken */
-
- if (mbhd->l2lnk != 0) /* Info Frame? */
-
- /*------------------------------*/
- /*--- Info Frame ---*/
- /*------------------------------*/
- {
- if ((getfid(orgnod, mbhd) /*== 1*/) /* Call des Quellknotens holen */
- &&(getfid(desnod, mbhd) /*== 1*/) /* Call des Zielknotens holen */
- &&(mbhd->getcnt < mbhd->putcnt)) /* Info im Frame? */
- {
- getchr(mbhd); /* Restlebensdauer ueberlesen */
- nxtsav = mbhd->nxtchr; /* Position im Frame merken */
- getsav = mbhd->getcnt;
- takfhd(mbhd); /* Header zerlegen */
- mbhd->nxtchr = nxtsav; /* wieder auf alten Stand */
- mbhd->getcnt = getsav;
-
- if ((cmpid(myid, orgnod) == 0) /* kein eigenes Frames */
- &&(isgood() /*== TRUE*/) /* und gute Qualitaet */
- &&(
- ((destin = iscall(orgnod)) == FALSE)
- ||(istweg(&txfhdr[14], &rxfhdr[7], rxfprt) == ERROR)
- )
- #ifdef MODIFIED
- && ( destin || (( no_slime & 2 ) == 0 ))
- #endif
- )
- {
- chgnod('+', obcini, 0, rxfprt, &txfhdr[14], &rxfhdr[7],
- (destin == FALSE)? &nulide[0] : &despoi->nodide[0],
- orgnod); /* Zielliste auf neuen Stand bringen */
- }
-
- if (cmpid(myid, desnod) /*== 1*/) /* Frame fuer mich? */
- {
- relink(mbhd, l4rxfl.lprev); /* dann an Level 4 geben */
- continue; /* naechstes Frame */
- }
-
- if (iscall(desnod) /*== 1*/ ) /* Ziel bekannt? */
- {
- if (--*(mbhd->nxtchr -1) != 0) /* noch Restlebensdauer? */
- {
- mbhd->nxtchr = rxnxt; /* auf Transportheader */
- mbhd->getcnt = rxgetc;
- if ((despoi->actrou != 0) /* aktiver Weg zum Ziel? */
- &&(mbhd->l2lnk ==
- despoi->weg[despoi->wegnr].nachba->nbrl2l))
- {
- despoi->actrou &=0xfff8;
- despoi->actrou |= 0x02;
- }
- if ((cmpid(myid, orgnod) == 0)
- || ((despoi->actrou & 0x07) == 2))
- {
- #ifdef STATSCMD
- l3gwcnt[0]++; /* bump gateway stats counter */
- #endif
- #ifdef L3MONITOR
- checkheard( &l3heardl, orgnod, l3mhlcnt );
- if ( l3mhlcnt )
- cpyid( mhptr->l3dest, desnod );
- #endif
- #ifdef ACL
- if( ( acl_mask & ACL_BAR_L3_RELAY ) &&
- (( acl_entry( orgnod ) & ACL_BAR_L3_RELAY )
- ||
- ( acl_entry( desnod ) & ACL_BAR_L3_RELAY ) ))
- dealmb( mbhd );
- else
- #endif
- {
- #ifdef PK96
- sta_led_on();
- #endif
- todest(mbhd); /* Info absetzen */
- #ifdef PK96
- sta_led_off();
- #endif
- }
- continue;
- } /* Info kann abgesetzt werden */
- } /* noch Restlebensdauer */
- } /* Ziel ist bekannt */
- } /* Info ist im Frame */
- } /* es ist ein I-Frame */
-
- /*--------------------------------------*/
- else /* UI Frame */
- {
- if (worqua != 0) /* darf Auswertung erfolgen? */
- {
- takfhd(mbhd); /* Header zerlegen */
- mbhd->nxtchr = rxnxt; /* zurueck auf Anfang */
- mbhd->getcnt = rxgetc;
-
- if (isgood() == TRUE)
- {
- if ((mbhd->getcnt < mbhd->putcnt) /* Info im Frame? */
- &&((getchr(mbhd) & 0xff) == 0xff) /* stimmt Signatur? */
- &&(ge6chr(beaide, mbhd) /*== 1*/) /* Ident des Knotens */
- &&(chgnod('+', obcini, qualty, rxfprt, &txfhdr[14],
- &rxfhdr[7], &beaide[0], &rxfhdr[7]) /*== 1*/))
- {
- while ((getfid(desnod, mbhd) /*== 1*/) /* Rest des Frames */
- && (ge6chr(beaide, mbhd) /*==1*/)
- && (getfid(nbrcal, mbhd) /*== 1*/)
- && (mbhd->getcnt < mbhd->putcnt))
- {
- chaqua = getchr(mbhd) & 0xff;
- if (cmpid(myid, desnod) == 0) /* selbst Ziel? */
- {
- if ((chaqua = (((chaqua * qualty) +128) / 256))
- >= worqua)
- {
- if (cmpid(myid, nbrcal) /*== 1*/)
- chaqua = 0;
- if (chgnod('+', obcini, chaqua, rxfprt,
- &txfhdr[14], &rxfhdr[7],
- ((chaqua == 0) && (iscall(desnod) != 0))?
- &despoi->nodide[0] : &beaide[0],
- desnod) == 0) break;
- } /* Qualitaet gut genug fuer Update */
- } /* nicht selbst das Ziel */
- } /* bis Framenende */
-
- if (nbrpoi != NULL)
- { /* Nachbar definiert */
- for (despoi = (nodtyp *) destil.lnext; /* Ziel? */
- despoi != (nodtyp *) &destil.lnext;
- despoi = (nodtyp *) despoi->nodlnk.lnext)
- {
- if (despoi->actrou != 0)
- { /* aktiver Weg zum Ziel? */
- for (cnt = 0; /* alle Wege des Zieles */
- despoi->wege > cnt;
- ++cnt)
- {
- if (despoi->weg[cnt].nachba == nbrpoi)
- { /* fuehrt der Weg ueber diesen Nachb */
- if (despoi->wegnr > cnt)
- { /* gibt es einen besseren Weg? */
- despoi->wegnr = cnt;
- makrou(); /* diesen Weg versuchen*/
- } /* es gibt einen besseren Weg*/
- break;
- } /* Weg fuehrt ueber diesen Nachbarn */
- } /* dieser Weg bearbeitet */
- } /* aktiver Weg existiert */
- } /* dieses Ziel bearbeitet */
- } /* Weg geht ueber einen Nachbarn */
- } /* Signatur ist gut */
- } /* Qualitaet des Kanals stimmt */
- } /* Auswertung zulaessig */
- } /* ist UI Frame */
- } /* PID stimmt */
- dealmb(mbhd); /* Frame ist bearbeitet, wegwerfen */
- } /* Frames in der Kette */
-
- /*=== zu sendende Frames verarbeiten ===*/
- while ((mbhd = (mhtyp *) l3txl.lnext) != (mhtyp *) &l3txl.lnext) { /* leer?*/
- unlink(mbhd); /* Frame aushaengen */
- despoi = (nodtyp *) mbhd->l2lnk; /* Pointer auf Nachbarn */
- if ((despoi->nodcal[0] != 0) /* Ziel definiert */
- && (nmbfre > 64)) { /* und Platz im Speicher */
- rwndmb(mbhd); /* alle Pointer auf Ausgangsstellung */
- getchr(mbhd); /* alles initialisieren */
- --mbhd->nxtchr;
- rxgetc = mbhd->putcnt; /* Framelaenge merken */
- mbhd->putcnt = 1; /* auf Anfang */
- putfid(myid, mbhd); /* Absender ins Frame */
- putfid(&despoi->nodcal[0], mbhd); /* Ziel ins Frame */
- *(mbhd->nxtchr -1) |= 1; /* Ende der Adresse setzen */
- putchr(timliv, mbhd); /* Lebensdauer setzen */
- mbhd->putcnt = rxgetc; /* Putcount zurueck */
- rwndmb(mbhd); /* Pointer wieder aufziehen */
- todest(mbhd); /* weg damit */
- }
- else dealmb(mbhd); /* geht nicht, Frame vernichten */
- }
-
- /*=== sonstige Funktionen ===*/
- for (despoi = (nodtyp *) destil.lnext; /* Zielliste bearbeiten */
- despoi != (nodtyp *) &destil.lnext;
- despoi = (nodtyp *) despoi->nodlnk.lnext) {
- switch (despoi->actrou & 0x07) { /* ueber Wegstatus verzweigen */
- /*------------------------------*/
- case 2: /* Fehler aufgetreten, neuen Weg nehmen */
- if (++despoi->wegnr >= despoi->wege) {
- if ((despoi->actrou & 0x80) == 0)
- despoi->wegnr = 0;
- else {
- destot(); /* Ziel nicht erreichbar, Frames wegwerfen */
- break;
- } }
- makrou(); /* Weg aufbauen */
- break;
-
- /*------------------------------*/
- case 3: /* Info Transfer laeuft */
- while ((mbhd = (mhtyp *) despoi->nodinf.lnext)
- != (mhtyp *) &despoi->nodinf)
- {
- unlink(mbhd); /* Frame aus Kette holen */
- mbhd->pid = PID_NETROM;/* PID setzen */
- relink(mbhd,
- (lnkpoi = despoi->weg[despoi->wegnr].nachba->nbrl2l)
- ->sendil.lprev); /* Frame in L2 umhaengen */
- ++lnkpoi->tosend; /* ein Frame mehr senden */
- lnkpoi->noatou = ininat; /* Timeout setzen */
- }
- break;
-
- /*------------------------------*/
- case 4: /* */
- makrou(); /* Weg aufbauen */
- break;
-
- /*------------------------------*/
- default: /* leer oder connect laeuft */
- break;
-
- } } }
-
- /*---------------------------------------------------------------------------*/
- VOID l2tol3(status) /* Level 2 meldet neuen Status */
- unsigned status; /* 0=nicht verwendet, 1=connected */
- /* 2=disconnected, 3=busy, 4=Failure */
- {
- register unsigned wegsts; /* Status des aktuellen Weges */
- register nbrtyp *nbrpoi; /* Pointer auf Nachbarn */
-
- if (status < 5) /* nicht alles verwenden */
- {
- for (despoi = (nodtyp *) destil.lnext; /* gemeldeten Link suchen */
- despoi != (nodtyp *) &destil.lnext;
- despoi = (nodtyp *) despoi->nodlnk.lnext)
- {
- if (((wegsts = despoi->actrou & 0x07) != 0) /* aktiver Weg? */
- && ((despoi->weg[despoi->wegnr].nachba)->nbrl2l == lnkpoi))
- {
- if (status == 1) /* Connect gemeldet */
- {
- if (wegsts == 1) /* und war auch gefordert */
- despoi->actrou = 3; /* neuer Status des Zieles: connected*/
- }
- else
- {
- if (wegsts != 4)
- {
- despoi->actrou &= 0xfff8; /* Busy: */
- despoi->actrou |= 0x02; /* neuer Status: anderen Weg */
- }
- }
- }
- }
- if (status != 1) /* bei Busy / Failure */
- {
- for (nbrpoi = (nbrtyp *) neigbl.lnext; /* Nachbar Liste absuchen */
- nbrpoi != (nbrtyp *) &neigbl.lnext;
- nbrpoi = (nbrtyp *) nbrpoi->nbrlnk.lnext)
- {
- if (nbrpoi->nbrl2l == lnkpoi)
- nbrpoi->nbrl2l = 0; /* Querverweis loeschen */
- }
- }
- }
- }
-
- /*---------------------------------------------------------------------------*/
- #ifdef MODIFIED
- /* brosrv()
- * This routine is called to make nodes b'casts. If the modified
- * version is used, it adds extra features as described in the
- * overview guide. To enable this its structure is different !
- */
- VOID brosrv() /* Rundspruchservice */
- /* jede Sekunde aufgerufen */
- {
- register unsigned cnt; /* Zaehler */
- register unsigned mask;
- register wegtyp *route; /* aktueller Weg */
-
- if( br1int != 0 ) /* assuming that the function is running, */
- if( ++br1tim >= br1int ) /* then bump timer and see if period expired */
- { /* if so, clear counter & do RS232 nodes */
- br1tim = 0;
- if( brochn & 2 )
- bronpo( ASYNPORT );
- }
- if (broint != 0) /* Rundspruch erlaubt? */
- {
- if (++brotim >= broint) /* Zeit zum Senden gekommen? */
- {
- brotim = 0; /* Uhr ruecksetzen */
- for (despoi = (nodtyp *) destil.lnext; /* Zielliste absuchen */
- despoi != (nodtyp *) &destil.lnext;
- despoi = (nodtyp *) despoi->nodlnk.lnext)
- {
- if (despoi->nodcal[0] != 0) /* Eintrag belegt? */
- {
- if (obcini != 0) /* wenn Abwesenheitszaehler gefuehrt wird */
- {
- for (cnt = 0; cnt < despoi->wege; ++cnt) /* alle Wege testen */
- {
- if (((route = &despoi->weg[cnt])->obscnt != 0) /* gueltig? */
- &&(--(route->obscnt) == 0)) /* gerade auf 0 angekommen? */
- {
- delrou(cnt); /* dann loeschen */
- --cnt; /* ein Weg weniger */
- }
- }
- }
- }
- }
- /* for each port, if bcast enabled for that port, and if RS232 nodes
- * broadcasts are going at a different rate and this is not the RS232
- * port, then broadcast nodes
- */
- for( cnt = 0, mask = 1; cnt < NUMPORTS; cnt++, mask <<= 1 )
- if( ( brochn & mask ) && ( br1int == 0 || cnt != ASYNPORT ))
- bronpo( cnt );
- }
- }
- }
-
- /* ---------------------------------------------------------------------------
- * This is the per channel nodes broadcast routine.
- * It is called by brosrv() to do a b'cast on a specified channel.
- *
- */
- VOID bronpo( kanal )
- register unsigned kanal;
- {
- register mhtyp *mbhd; /* Buffer fuer Meldung */
- register wegtyp *route; /* aktueller Weg */
- unsigned algorithm, nohash;
-
- /* if algorithm flag is TRUE, then do not broadcast a node if its best
- * quality neighbour is on the same port
- */
- algorithm = broalg & ( 1 << kanal );
- nohash = nohashnode & ( 1<< kanal );
-
- mbhd = brobuf(); /* Buffer besorgen */
- for (despoi = (nodtyp *) destil.lnext; /* Zielliste absuchen */
- despoi != (nodtyp *) &destil.lnext;
- despoi = (nodtyp *) despoi->nodlnk.lnext)
- {
- if (despoi->nodcal[0] != 0) /* Eintrag belegt? */
- {
- if (((route = &despoi->weg[0])->qualit != 0) /* Qualitaet */
- &&( algorithm == 0 || route->nachba->nbrpor != kanal )
- &&( nohash != 0 ? despoi->nodide[0] != '#' : 1 )
- &&((route->obscnt == 0) /* muss sein, Eintrag permanent oder */
- || ((route->obscnt & 0xff) >= obcbro))) /* gut genug */
- {
- if (mbhd == 0) /* ggfs neuen Buffer besorgen */
- mbhd = brobuf();
-
- putfid(&despoi->nodcal[0], mbhd); /* Call des Zieles */
- pu6chr(&despoi->nodide[0], mbhd); /* Ident des Zieles */
- putfid(&route->nachba->nbrcal[0], mbhd); /* Nachbar des Zieles */
- putchr(route->qualit, mbhd); /* Qualitaet zum Ziel */
- if ((mbhd->putcnt + 21) > 256) /* droht Ueberlauf? */
- {
- sdbufr(mbhd, kanal); /* dann Buffer senden */
- mbhd = 0; /* Buffer ist weg */
- }
- }
- }
- }
- if (mbhd != 0) /* noch Reste im Buffer? */
- sdbufr(mbhd, kanal); /* dann senden */
- }
-
- /*---------------------------------------------------------------------------*/
- VOID sdbufr(mbhd, kanal) /* Buffer als Rundspruch senden */
- register mhtyp *mbhd;
- {
- mbhd->pid = PID_NETROM; /* PID = Level3 */
- rwndmb(mbhd); /* Pointer aufziehen */
- sdui(&brodil[0], &brodes[0], &myid[0], kanal, mbhd); /* Level2 sendet */
- dealmb(mbhd); /* Buffer wieder freigeben */
- }
-
- #else
- /* --------------------------------------------------------------------------
- * this is the original ( almost ) brosrv()
- */
- VOID brosrv() /* Rundspruchservice */
- /* jede Sekunde aufgerufen */
- {
- register unsigned cnt; /* Zaehler */
- register mhtyp *mbhd; /* Buffer fuer Meldung */
- register wegtyp *route; /* aktueller Weg */
-
- if (broint != 0) { /* Rundspruch erlaubt? */
- if (++brotim >= broint) { /* Zeit zum Senden gekommen? */
- brotim = 0; /* Uhr ruecksetzen */
- mbhd = brobuf(); /* Buffer besorgen */
-
- for (despoi = (nodtyp *) destil.lnext; /* Zielliste absuchen */
- despoi != (nodtyp *) &destil.lnext;
- despoi = (nodtyp *) despoi->nodlnk.lnext) {
- if (despoi->nodcal[0] != 0) { /* Eintrag belegt? */
- if (obcini != 0) { /* wenn Abwesenheitszaehler gefuehrt wird */
- for (cnt = 0; /* alle Wege testen */
- cnt < despoi->wege;
- ++cnt) {
- if (((route = &despoi->weg[cnt])->obscnt != 0) /* gueltig? */
- &&(--(route->obscnt) == 0)) { /* gerade auf 0 angekommen? */
- delrou(cnt); /* dann loeschen */
- --cnt; /* ein Weg weniger */
- } }
- if (despoi->nodcal[0] == 0) /* gibt es den Weg noch? */
- continue;
- }
- if (((route = &despoi->weg[0])->qualit != 0) /* Qualitaet */
- &&((route->obscnt == 0) /* muss sein, Eintrag permanent oder */
- || ((route->obscnt & 0xff) >= obcbro))){ /* gut genug */
-
- if (mbhd == 0) /* ggfs neuen Buffer besorgen */
- mbhd = brobuf();
-
- putfid(&despoi->nodcal[0], mbhd); /* Call des Zieles */
- pu6chr(&despoi->nodide[0], mbhd); /* Ident des Zieles */
- putfid(&route->nachba->nbrcal[0], mbhd); /* Nachbar des Zieles */
- putchr(route->qualit, mbhd); /* Qualitaet zum Ziel */
- if ((mbhd->putcnt + 21) > 256) { /* droht Ueberlauf? */
- sdbufr(mbhd); /* dann Buffer senden */
- mbhd = 0; /* Buffer ist weg */
- }
- }
- } }
- if (mbhd != 0) /* noch Reste im Buffer? */
- sdbufr(mbhd); /* dann senden */
- } } }
-
- /*---------------------------------------------------------------------------*/
- VOID sdbufr(mbhd) /* Buffer als Rundspruch senden */
- mhtyp *mbhd;
- {
- register unsigned kanal; /* Kanal, auf dem gesendet wird */
- mbhd->pid = PID_NETROM; /* PID = Level3 */
- for (kanal = 0;
- kanal < 2; /* auf beiden Kanaelen senden */
- ++kanal)
- {
- rwndmb(mbhd); /* Pointer aufziehen */
- sdui(&brodil[0], &brodes[0], &myid[0], kanal, mbhd); /* Level2 sendet */
- }
- dealmb(mbhd); /* Buffer wieder freigeben */
- }
-
- #endif /* MODIFIED brosrv() */
-
- /*---------------------------------------------------------------------------*/
- mhtyp *brobuf() /* Buffer fuer Rundspruch besorgen */
- {
- register mhtyp *mbhd; /* Buffer fuer Meldung */
-
- putchr(0xff, (mbhd = allocb())); /* Buffer besorgen, Signatur rein */
- pu6chr(alias, mbhd); /* Ident in Buffer */
- return(mbhd); /* Buffer als Rueckgabe */
- }
-
- /*---------------------------------------------------------------------------*/
- BOOLEAN chgnod(mode, obci, quali, port, digis, nachb, iden, call)
- /* Zieleintrag aendern */
- unsigned mode; /* '+'=neuer Eintrag, '-'=Eintrag loeschen */
- unsigned obci; /* Abwesenheitszaehler, Initialisierung */
- unsigned quali; /* Qualitaet des Weges */
- unsigned port; /* Port zum Ziel */
- char *digis; /* Digipeaterliste */
- char *nachb; /* Nachbar zum Ziel */
- char *iden; /* Ident des Zieles */
- char *call; /* Rufzeichen des Zieles */
-
- /* Rueckgabe: */
- /* TRUE: loeschen verlangt, kein Eintrag da */
- /* aendern war erfolgreich */
- /* FALSE: Liste voll */
- {
- register unsigned cnt; /* Scratch Zaehler */
- register char *id1poi; /* Pointer fuer Call-Ident Vergleich */
- char *id2poi; /* Pointer fuer Call-Ident Vergleich */
- unsigned rout; /* aktueller Weg */
- register nodtyp *ziel1; /* Pointer auf Ziel */
- nodtyp *zielpt; /* Pointer auf Ziel */
-
- zielpt = NULL;
- for (despoi = (nodtyp *) destil.lnext; /* Zielliste absuchen */
- despoi != (nodtyp *) &destil.lnext;
- despoi = (nodtyp *) despoi->nodlnk.lnext)
- {
- if (despoi->nodcal[0] != 0) { /* Eintrag belegt? */
- if (cmpid(&despoi->nodcal[0], call) /*== 1*/) break; /* und passt? */
- }
- else { /* freier Eintrag */
- if (zielpt == NULL) zielpt = despoi; /* ersten freien Eintrag merken */
- }
- }
- if ((nodtyp *) &destil.lnext == despoi) { /* passender Eintrag? */
- if (mode == '+') { /* hinzufuegen? */
- if (zielpt == 0) { /* kein freier Platz bisher? */
- if (numdes < maxdes) { /* Liste hat noch Platz? */
- (zielpt = (nodtyp *) allocb())->actrou = 0; /* initialisieren */
- zielpt->wege = 0; /* kein Weg bekannt */
- inithd(&zielpt->nodinf); /* keine Info in der Schlange */
- relink(zielpt, destil.lprev); /* in Zielliste haengen */
- ++numdes; /* Liste ist laenger geworden */
- }
- else return (FALSE); /* Liste ist voll */
- }
- despoi = zielpt; /* freien (neuen) Platz nehmen */
- cpyid(&despoi->nodcal[0], call); /* Call eintragen, Rest spaeter */
- }
- else return (TRUE); /* loeschen verlangt, Eintrag existiert nicht*/
- }
-
- /*------------------------------ passender Eintrag existiert (CALL) */
- cpy6ch(&despoi->nodide[0], iden); /* Ident umkopieren */
- unlink(despoi); /* Eintrag aus Kette loesen */
-
- for (ziel1 = (nodtyp *) destil.lnext; /* Zielliste absuchen */
- ziel1 != (nodtyp *) &destil.lnext;
- ziel1 = (nodtyp *) ziel1->nodlnk.lnext)
- {
- id1poi = (char *) &ziel1->nodide[0];
- id2poi = (char *) &despoi->nodide[0];
- for (cnt = 13; cnt != 0; --cnt)
- { /* Call und Ident vergleichen */
- if (*id1poi == *id2poi)
- {
- ++id1poi;
- ++id2poi;
- }
- else break;
- } /* Call und Ident verglichen */
- if (*id1poi > *id2poi) break;
- } /* Zielliste abgesucht */
- relink(despoi, ziel1->nodlnk.lprev);
- if ((rout = istweg(digis, nachb, port)) == -1)
- {
- if (mode == '+')
- newnod(obci, quali, port, digis, nachb);
- }
- else
- {
- if (mode == '-')
- delrou(rout);
- else
- {
- if (despoi->weg[rout].obscnt != 0)
- addweg(obci, quali, rout);
- }
- }
- return (TRUE);
- }
-
- /*---------------------------------------------------------------------------*/
- VOID newnod(obci, quali, port, digis, nachb)
- /* Zieleintrag in Liste aufnehmen */
- unsigned obci; /* Anwesenheitszaehler */
- unsigned quali; /* Qualitaet des Weges */
- unsigned port; /* Port zum Ziel */
- char *digis; /* Digipeaterliste */
- char *nachb; /* Nachbar zum Ziel */
- {
- register unsigned neuweg; /* Position des neuen Weges in Liste */
- register wegtyp *wegptr; /* Pointer auf Weg */
- register nbrtyp *nbrptr; /* Pointer auf Nachbarn */
-
- rouhin(); /* alle Wege in Arbeitsspeicher */
- (wegptr = &routmp[despoi->wege]) /* auf neuen Weg. wege zaehlt 1-2-3! */
- ->qualit = quali; /* Qualitaet des neuen Weges */
- wegptr->obscnt = obci; /* Anwesenheitszaehler */
- wegptr->nachba = (nbrtyp *) -1; /* Zeiger auf Nachbarn loeschen */
- neuweg = srtrou(despoi->wege++); /* Wege sortieren */
- rouher(); /* Wege zurueck in Liste */
- if (neuweg < 3) /* steht der neue Weg in der Liste? */
- {
- ++(nbrptr = updnbr(digis, nachb, port)) /* Nachbarnliste neuer Stand */
- ->nbrrou; /* ein Weg mehr ueber diesen Nachbarn */
- despoi->weg[neuweg].nachba = nbrptr; /* Nachbarn in Zielliste eintragen*/
- }
- if (despoi->wege > 3) { /* nun mehr als 3 Wege vorhanden? */
- --despoi->wege; /* darf nicht sein */
- if (neuweg < 3) /* wurde neuer Weg in die Liste aufgenommen? */
- decrcn(&routmp[3]); /* dann muss ein anderer entfernt werden */
- }
- if ((despoi->actrou != 0) /* besteht ein aktiver Weg? */
- && (despoi->wegnr > 2)) { /* und ist es der nun schlechteste? */
- despoi->wegnr = 0; /* dann den besten nehmen */
- makrou(); /* und Link neu aufbauen */
- }
- }
-
- /*---------------------------------------------------------------------------*/
- VOID addweg(obci, quali, nummer)
- /* Weg in Liste aufnehmen */
- unsigned obci; /* Anwesenheitszaehler */
- unsigned quali; /* Qualitaet des Weges */
- unsigned nummer; /* Nummer des Eintrages */
- {
- register wegtyp *wegptr; /* Pointer auf Weg */
-
- (wegptr = &(despoi->weg[nummer]))->qualit = quali; /* Qualitaet */
- wegptr->obscnt = obci; /* und Anwesenheitszaehler setzen */
- rouhin(); /* auslagern in Arbeitsspeicher */
- srtrou(-1); /* sortieren */
- rouher(); /* zurueck in Liste */
- }
-
- /*---------------------------------------------------------------------------*/
- VOID delrou(nummer) /* Weg aus Liste streichen */
- unsigned nummer; /* Nummer des Eintrages */
- {
- register wegtyp *wegptr; /* Pointer auf Weg */
-
- decrcn(wegptr = &(despoi->weg[nummer])); /* Weg in Nachbarnliste loeschen */
- if (despoi->wege > 1) { /* nun noch Wege fuer dieses Ziel vorhanden? */
- wegptr->nachba = 0; /* ohne Nachbarn hat der Weg keine Qualitaet */
- rouhin(); /* Wege in Arbeitsspeicher */
- srtrou(-1); /* sortieren */
- rouher(); /* wieder in Liste zurueck */
- }
- else { /* den letzten Weg entfernt */
- destot(); /* Ziel existiert nicht mehr */
- despoi->nodcal[0] = 0; /* Eintrag ist wieder frei */
- }
- if ((despoi->wegnr >= --despoi->wege) /* aktiven Weg geloescht? */
- && (despoi->actrou != 0)) {
- despoi->wegnr = 0; /* neuen Weg suchen */
- makrou();
- }
- }
-
- /*---------------------------------------------------------------------------*/
- VOID decrcn(weg) /* Weg aus Nachbarn-Liste streichen */
- wegtyp *weg; /* zu loeschender Weg */
- {
- register nbrtyp *nbrptr; /* Pointer auf Nachbarn */
-
- if ((--(nbrptr = weg->nachba)->nbrrou == 0) /* den letzten Weg geloescht? */
- && (nbrptr->locked == 0)) /* und Eintrag nicht gesperrt */
- {
- dealoc(unlink(nbrptr)); /* dann Nachbarn komplett loeschen */
- }
- }
-
- /*---------------------------------------------------------------------------*/
- VOID rouhin() /* Wege in Arbeitsspeicher auslagern */
- {
- move4b(3, routmp, &despoi->weg[0]); /* 12 (=3*4) Bytes kopieren */
- }
-
- /*---------------------------------------------------------------------------*/
- VOID rouher() /* Wege aus Arbeitsspeicher holen */
- {
- move4b(3, &despoi->weg[0], routmp); /* 12 (=3*4) Bytes kopieren */
- }
-
- /*---------------------------------------------------------------------------*/
- unsigned srtrou(wegneu) /* Wegeliste in routmp sortieren */
- int wegneu; /* Position des neuen Weges in routmp */
- /* Rueckgabe: Position des neuen Weges */
- {
- unsigned wegcnt; /* Zahl der Wege in routmp */
- unsigned waktiv; /* aktiver Weg dieses Zieles */
- unsigned akt; /* aktuell untersuchter Weg (Nummer) */
- register unsigned nxt; /* naechster zu untersuchender Weg (Nummer) */
- register wegtyp *wakt; /* aktueller Weg */
- register wegtyp *wnxt; /* naechster Weg */
-
- wegcnt = despoi->wege; /* Zahl der Wege holen */
- waktiv = despoi->wegnr; /* aktiven Weg merken */
- for (wakt = &routmp[akt = 0]; /* Bubble Sort ueber routmp */
- (wegcnt-1) > akt;
- ++akt, ++wakt) {
- for (wnxt = &routmp[nxt = akt + 1];
- nxt < wegcnt;
- ++nxt, ++wnxt) {
- if ((! wakt->nachba) /* der Weg muss einen Nachbarn haben */
- || ((wakt->qualit & 0xff) < (wnxt->qualit & 0xff))) { /* und besser */
- move4b(1, &rouwrk, wakt); /* als der vorherige sein */
- move4b(1, wakt, wnxt); /* dann die Wege tauschen */
- move4b(1, wnxt, &rouwrk);
- if (wegneu == akt) wegneu = nxt; /* neuen Weg merken */
- else if (wegneu == nxt) wegneu = akt;
- if (waktiv == akt) waktiv = nxt; /* aktiven Weg merken */
- else if (waktiv == nxt) waktiv = akt;
- } } }
- despoi->wegnr = waktiv; /* aktiven Weg in Liste korrigieren */
- return(wegneu); /* mit Position des neuen Weges zurueck */
- }
-
- /*---------------------------------------------------------------------------*/
- /* we have a macro version for this - so only use it if
- * the macro has not been included.
- */
- #ifndef move4b
- VOID move4b(zahl, nach, von) /* 4 * Zahl Bytes kopieren */
- unsigned zahl;
- register char *nach; /* Ziel */
- register char *von; /* Quelle */
- {
- register unsigned cnt; /* Scratch Zaehler */
-
- for (cnt = 0; (zahl * 4) > cnt; ++cnt) {
- *nach++ = *von++;
- }
- }
- #endif
-
- /*---------------------------------------------------------------------------*/
- VOID todest(mbhd) /* Info in Zielliste haengen */
- mhtyp *mbhd; /* Info Header */
- {
- relink(mbhd, despoi->nodinf.lprev); /* Info umhaengen */
- if (despoi->actrou == 0) { /* kein aktiver Weg da? */
- despoi->wegnr = 0; /* mit dem besten Weg beginnend */
- makrou(); /* Link aufbauen */
- }
- }
-
- /*---------------------------------------------------------------------------*/
- VOID makrou() /* Weg zu einem Ziel aufbauen */
- {
- register unsigned cnt; /* Scratch Zaehler */
- register l2ltyp *l2poi; /* Pointer auf Level2 Kontrollblock */
- register nbrtyp *nbrpoi; /* Pointer auf Nachbarn */
-
- if (despoi->nodinf.lnext != (lhtyp *) &despoi->nodinf.lnext) { /* Info? */
- despoi->actrou &= 0xfff8; /* Status: kein aktiver Weg */
- if ((lnkpoi = /* schon - noch Eintrag fuer L2 vorhanden? */
- (nbrpoi = despoi->weg[despoi->wegnr].nachba)->nbrl2l)
- == 0) {
- for (l2poi = 0, cnt = 0, lnkpoi = &lnktbl[0];
- cnt < MAXL2L; /* nein, freien Eintrag suchen */
- ++cnt, ++lnkpoi) {
- if (lnkpoi->state != 0) { /* Eintrag belegt */
- if ((cmpid(nbrpoi->nbrcal, lnkpoi->dstid) /*== 1*/)
- &&(cmpid(myid, lnkpoi->srcid) /*== 1*/)
- &&(lnkpoi->liport == nbrpoi->nbrpor))
- break; /* passt er zufaellig? Dann benutzen */
- }
- else { /* Eintrag ist frei */
- if ((l2poi == 0) && (lnkpoi->srcid[0] == 0))
- l2poi = lnkpoi; /* ersten freien Eintrag merken */
- }
- }
- if (cnt == MAXL2L) { /* kein passender Eintrag gefunden? */
- if (l2poi != 0) { /* freier Eintrag vorhanden? */
- lnkpoi = l2poi; /* dann nehmen wir ihn */
- cpyid(lnkpoi->srcid, myid); /* Quellcall eintragen */
- cpyid(lnkpoi->dstid, nbrpoi->nbrcal); /* Zielcall eintragen */
- cpyidl(lnkpoi->viaid, nbrpoi->nbrdil); /* Digiliste eintragen */
- lnkpoi->liport = nbrpoi->nbrpor; /* Port eintragen */
- newlnk(); /* im Level 2 eine Verbindung bestellen */
- }
- else { /* L2 Tabelle ist voll */
- despoi->actrou |= 0x02; /* Fehler markieren */
- return; /* Abbruch */
- }
- }
- nbrpoi->nbrl2l = lnkpoi; /* in Nachbarnliste Querverweis eintragen */
- }
- if (lnkpoi->state == 1) /* Status = Connect laeuft? */
- despoi->actrou |= 0x01; /* dann auch in Nachbarnliste so markieren */
- else
- {
- if (lnkpoi->state == 3) /* Status: Disc-Requested? */
- despoi->actrou |= 0x04;
- else
- despoi->actrou = 3; /* sonst Status = connected */
- }
- if ((despoi->actrou == 1) /* Connect laeuft und */
- && (despoi->wegnr == 0)) /* noch kein Weg probiert */
- despoi->actrou |= 0x80; /* markieren */
- }
- else despoi->actrou = 0; /* keine aktive Route */
- }
-
- /*---------------------------------------------------------------------------*/
- VOID destot() /* Ziel ist nicht mehr erreichbar */
- {
- dealml(&despoi->nodinf); /* Info fuer das Ziel wegwerfen */
- despoi->actrou = 0; /* kein aktiver Weg */
- }
-
- /*---------------------------------------------------------------------------*/
- BOOLEAN isgood() /* Entscheidung ueber Qualitaet des Weges */
- { /* TRUE: Qualitaet ist gut fuer Speicherung */
- return ( /* FALSE: schlechter Weg */
- #ifdef ACL
- !( ( acl_mask & ACL_BAR_L3_BCASTS ) &&
- ( acl_entry( &rxfhdr[7] ) & ACL_BAR_L3_BCASTS ) ) &&
- #endif
- (qualty = (
- (nbrpoi = getnei(&txfhdr[14], &rxfhdr[7], rxfprt)) /* welcher Nachbar? */
- == NULL)? /* existiert er ueberhaupt? */
- ((rxfprt == 0)? ch0qua : ch1qua) /* Portqualitaet, wenn nicht da */
- :
- (nbrpoi->pathqu & 0xff)) /* sonst aus Nachbarliste */
- >= worqua); /* vergleichen mit Minimalqualitaet */
- }
-
- /*---------------------------------------------------------------------------*/
- nbrtyp *updnbr(digis, nachb, port) /* Nachbar auf neuen Stand bringen */
- char *digis; /* Digiliste zum Nachbarn */
- char *nachb; /* Call des Nachbarn */
- unsigned port; /* Port zum Nachbarn */
- {
- register nbrtyp *nbrbuf; /* Buffer fuer Eintrag */
-
- if ((nbrbuf = getnei(digis, nachb, port)) == NULL)
- { /* Eintrag existiert noch nicht */
- nbrbuf = (nbrtyp *) allocb(); /* Buffer beschaffen */
- cpyid(&nbrbuf->nbrcal[0], nachb); /* Call eintragen */
- digis[14] = 0; /* nur 2 Digis */
- cpyidl(&nbrbuf->nbrdil[0], digis); /* Digiliste eintragen */
- nbrbuf->pathqu =
- ((nbrbuf->nbrpor = port) == 0)?
- ch0qua : ch1qua;
- nbrbuf->locked =
- nbrbuf->nbrrou = 0;
- nbrbuf->nbrl2l = NULL;
- relink(nbrbuf, neigbl.lprev);
- }
- return(nbrbuf); /* mit Pointer auf Eintrag zurueck */
- }
-
- /*---------------------------------------------------------------------------*/
- nbrtyp *getnei(digis, name, port) /* Nachbarn suchen */
- char *digis;
- char *name;
- unsigned port;
- {
- register nbrtyp *nachb;
-
- for (nachb = (nbrtyp *) neigbl.lnext;
- nachb != (nbrtyp *) &neigbl.lnext;
- nachb = (nbrtyp *) nachb->nbrlnk.lnext)
- {
- if (isneig(digis, name, port, nachb) /*== TRUE*/)
- return (nachb);
- }
- return(NULL);
- }
-
- /*---------------------------------------------------------------------------*/
- nbrprt(call) /* Port fuer Ziel "call" suchen? */
- char *call;
- {
- register nbrtyp *nachb; /* aktueller Nachbar */
-
- for (nachb = (nbrtyp *) neigbl.lnext; /* Nachbarnliste absuchen */
- nachb != (nbrtyp *) &neigbl.lnext;
- nachb = (nbrtyp *) nachb->nbrlnk.lnext)
- {
- if (cmpid(call, nachb->nbrcal) /*== TRUE*/)
- {
- return(nachb->nbrpor);
- }
- }
-
- if (isidnt(call) /*== TRUE*/)
- {
- for (nachb = (nbrtyp *) neigbl.lnext;
- nachb != (nbrtyp *) &neigbl.lnext;
- nachb = (nbrtyp *) nachb->nbrlnk.lnext)
- {
- if (cmpid(&nachb->nbrcal[0], &despoi->nodcal[0]) /*== TRUE*/)
- return(nachb->nbrpor);
- }
- }
- return(0); /* HDLC als default */
- }
-
- /*---------------------------------------------------------------------------*/
- BOOLEAN iscall(call) /* ist Call als Ziel eingetragen? */
- char *call;
- {
- for (despoi = (nodtyp *) destil.lnext; /* Zielliste absuchen */
- despoi != (nodtyp *) &destil.lnext;
- despoi = (nodtyp *) despoi->nodlnk.lnext) {
- if (despoi->nodcal[0] != 0) { /* Eintrag definiert? */
- if (cmpid(call, despoi->nodcal) /*== 1*/) /* dann testen */
- return(TRUE);
- } }
- return(FALSE);
- }
-
- /*---------------------------------------------------------------------------*/
- BOOLEAN isidnt(ident) /* ist Ident als Ziel eingetragen? */
- char *ident;
- {
- for (despoi = (nodtyp *) destil.lnext; /* Zielliste absuchen */
- despoi != (nodtyp *) &destil.lnext;
- despoi = (nodtyp *) despoi->nodlnk.lnext) {
- if (despoi->nodcal[0] != 0) { /* Eintrag definiert? */
- if (cmpcal(ident, despoi->nodide) /*== 1*/) /* dann testen */
- return(TRUE);
- } }
- return(FALSE);
- }
-
- /*---------------------------------------------------------------------------*/
- istweg(digis, call, port) /* Test, ob ein Weg existiert */
- char *digis; /* Digiliste */
- char *call; /* Call des Nachbarn */
- char port; /* Port fuer den Weg */
- { /* Rueckgabe: Weg-Nummer */
- register unsigned cnt; /* Scratch Zaehler */
-
- for (cnt = 0;
- cnt < despoi->wege;
- ++cnt) /* alle Wege zum Ziel testen */
- {
- if (isneig(digis, call, port, despoi->weg[cnt].nachba) /*== TRUE*/)
- return(cnt);
- }
- return(-1); /* Fehler, nicht gefunden */
- }
-
- /*---------------------------------------------------------------------------*/
- /* we do not need this if the more complex integrity checker is included
- */
- #ifndef INTEGRITY
- BOOLEAN isrout(buffer) /* Test, ob buffer in Weglisten ist */
- nbrtyp *buffer;
- {
- register nbrtyp *nachb;
-
- for (nachb = (nbrtyp *) neigbl.lnext; /* Nachbarnliste absuchen */
- nachb != (nbrtyp *) &neigbl.lnext;
- nachb = (nbrtyp *) nachb->nbrlnk.lnext)
- {
- if (nachb == buffer) return(TRUE);
- }
-
- for (despoi = (nodtyp *) destil.lnext; /* Zielliste absuchen */
- despoi != (nodtyp *) &destil.lnext;
- despoi = (nodtyp *) despoi->nodlnk.lnext)
- {
- if (despoi == (nodtyp *) buffer) return(TRUE);
- }
- return(FALSE); /* nicht gefunden */
- }
- #endif
-
- /*---------------------------------------------------------------------------*/
- BOOLEAN isneig(digis, call, port, nachb) /* Test, ob Daten in Nachbarliste */
- char *digis; /* Digipeaterliste */
- char *call; /* Call */
- char port; /* Port */
- register nbrtyp *nachb; /* Pointer auf vermuteten Eintrag in Liste */
- {
- return((nachb->nbrpor == port)
- && (cmpid(nachb->nbrcal, call) /*== 1*/)
- && (cmpidl(nachb->nbrdil, digis) /*== 1*/));
- }
-
- /*---------------------------------------------------------------------------*/
- BOOLEAN ge6chr(buffer, mbhd) /* 6 Zeichen aus mbhd nach Buffer */
- register char *buffer; /* Rueckgabe: TRUE=hat funktioniert */
- register mhtyp *mbhd;
- {
- register unsigned cnt; /* Zaehler */
-
- if ((mbhd->putcnt - mbhd->getcnt) >= 6) { /* genug Zeichen da? */
- for (cnt = 6; cnt != 0; --cnt) {
- *buffer++ = getchr(mbhd); /* Zeichen holen, ablegen */
- }
- return(TRUE); /* Erfolg melden */
- }
- else return(FALSE); /* nicht genug Zeichen im mbhd */
- }
-
- /*---------------------------------------------------------------------------*/
- VOID pu6chr(buffer, mbhd) /* 6 Zeichen aus Buffer in mbhd */
- register char *buffer;
- register mhtyp *mbhd;
- {
- register unsigned cnt; /* Zaehler */
-
- for (cnt = 6; cnt != 0; --cnt) {
- putchr(*buffer++, mbhd);
- } }
-
- /*---------------------------------------------------------------------------*/
- /* as for move4b, we have a quicker way of doing this .....
- * BUT BE CAREFUL - it is a macro so paramaters must be set carefully !
- */
- #ifndef cpy6ch
- VOID cpy6ch(dest, src)
- register char *src;
- register char *dest;
- {
- register unsigned cnt;
-
- for (cnt = 0; cnt < 6; ++cnt)
- {
- *dest++ = *src++;
- }
- }
- #endif
-
- /*- Ende Level 3 ------------------------------------------------------------*/